/**
 * Gemini API 处理函数模块
 *
 * 该模块包含所有 Gemini API 的处理函数，供 geminiRoutes.js 和 standardGeminiRoutes.js 共享使用。
 * 这样可以避免代码重复，确保处理逻辑的一致性。
 */

const logger = require('../utils/logger')
const geminiAccountService = require('../services/geminiAccountService')
const geminiApiAccountService = require('../services/geminiApiAccountService')
const { sendGeminiRequest, getAvailableModels } = require('../services/geminiRelayService')
const crypto = require('crypto')
const sessionHelper = require('../utils/sessionHelper')
const unifiedGeminiScheduler = require('../services/unifiedGeminiScheduler')
const apiKeyService = require('../services/apiKeyService')
const { updateRateLimitCounters } = require('../utils/rateLimitHelper')
const { parseSSELine } = require('../utils/sseParser')
const axios = require('axios')
const ProxyHelper = require('../utils/proxyHelper')

// ============================================================================
// 工具函数
// ============================================================================

/**
 * 构建 Gemini API URL
 * 兼容新旧 baseUrl 格式：
 * - 新格式（以 /models 结尾）: https://xxx.com/v1beta/models -> 直接拼接 /{model}:action
 * - 旧格式（不以 /models 结尾）: https://xxx.com -> 拼接 /v1beta/models/{model}:action
 *
 * @param {string} baseUrl - 账户配置的基础地址
 * @param {string} model - 模型名称
 * @param {string} action - API 动作 (generateContent, streamGenerateContent, countTokens)
 * @param {string} apiKey - API Key
 * @param {object} options - 额外选项 { stream: boolean, listModels: boolean }
 * @returns {string} 完整的 API URL
 */
function buildGeminiApiUrl(baseUrl, model, action, apiKey, options = {}) {
  const { stream = false, listModels = false } = options

  // 移除末尾的斜杠（如果有）
  const normalizedBaseUrl = baseUrl.replace(/\/+$/, '')

  // 检查是否为新格式（以 /models 结尾）
  const isNewFormat = normalizedBaseUrl.endsWith('/models')

  let url
  if (listModels) {
    // 获取模型列表
    if (isNewFormat) {
      // 新格式: baseUrl 已包含 /v1beta/models，直接添加查询参数
      url = `${normalizedBaseUrl}?key=${apiKey}`
    } else {
      // 旧格式: 需要拼接 /v1beta/models
      url = `${normalizedBaseUrl}/v1beta/models?key=${apiKey}`
    }
  } else {
    // 模型操作 (generateContent, streamGenerateContent, countTokens)
    const streamParam = stream ? '&alt=sse' : ''

    if (isNewFormat) {
      // 新格式: baseUrl 已包含 /v1beta/models，直接拼接 /{model}:action
      url = `${normalizedBaseUrl}/${model}:${action}?key=${apiKey}${streamParam}`
    } else {
      // 旧格式: 需要拼接 /v1beta/models/{model}:action
      url = `${normalizedBaseUrl}/v1beta/models/${model}:${action}?key=${apiKey}${streamParam}`
    }
  }

  return url
}

/**
 * 生成会话哈希
 */
function generateSessionHash(req) {
  const apiKeyPrefix =
    req.headers['x-api-key']?.substring(0, 10) || req.headers['x-goog-api-key']?.substring(0, 10)

  const sessionData = [req.headers['user-agent'], req.ip, apiKeyPrefix].filter(Boolean).join(':')

  return crypto.createHash('sha256').update(sessionData).digest('hex')
}

/**
 * 检查 API Key 权限
 */
function checkPermissions(apiKeyData, requiredPermission = 'gemini') {
  const permissions = apiKeyData?.permissions || 'all'
  return permissions === 'all' || permissions === requiredPermission
}

/**
 * 确保请求具有 Gemini 访问权限
 */
function ensureGeminiPermission(req, res) {
  const apiKeyData = req.apiKey || {}
  if (checkPermissions(apiKeyData, 'gemini')) {
    return true
  }

  logger.security(
    `🚫 API Key ${apiKeyData.id || 'unknown'} 缺少 Gemini 权限，拒绝访问 ${req.originalUrl}`
  )

  res.status(403).json({
    error: {
      message: 'This API key does not have permission to access Gemini',
      type: 'permission_denied'
    }
  })
  return false
}

/**
 * 权限检查中间件
 */
function ensureGeminiPermissionMiddleware(req, res, next) {
  if (ensureGeminiPermission(req, res)) {
    return next()
  }
  return undefined
}

/**
 * 应用速率限制跟踪
 */
async function applyRateLimitTracking(req, usageSummary, model, context = '') {
  if (!req.rateLimitInfo) {
    return
  }

  const label = context ? ` (${context})` : ''

  try {
    const { totalTokens, totalCost } = await updateRateLimitCounters(
      req.rateLimitInfo,
      usageSummary,
      model
    )

    if (totalTokens > 0) {
      logger.api(`📊 Updated rate limit token count${label}: +${totalTokens} tokens`)
    }
    if (typeof totalCost === 'number' && totalCost > 0) {
      logger.api(`💰 Updated rate limit cost count${label}: +$${totalCost.toFixed(6)}`)
    }
  } catch (error) {
    logger.error(`❌ Failed to update rate limit counters${label}:`, error)
  }
}

/**
 * 判断对象是否为可读流
 */
function isReadableStream(value) {
  return value && typeof value.on === 'function' && typeof value.pipe === 'function'
}

/**
 * 清理 contents 中 functionResponse 不被标准 Gemini API 支持的字段
 * 标准 Gemini API (generativelanguage.googleapis.com) 的 functionResponse 只支持 name 和 response 字段，不支持 id 字段
 * 注意：此函数仅用于 API Key 账户，OAuth 账户使用的 Cloud Code Assist API 可能支持额外字段
 */
function sanitizeFunctionResponsesForApiKey(contents) {
  if (!contents || !Array.isArray(contents)) {
    return contents
  }

  return contents.map((content) => {
    if (!content.parts || !Array.isArray(content.parts)) {
      return content
    }

    const sanitizedParts = content.parts.map((part) => {
      if (part.functionResponse) {
        // 只保留标准 Gemini API 支持的字段：name 和 response
        const { name, response } = part.functionResponse
        return {
          functionResponse: {
            name,
            response
          }
        }
      }
      return part
    })

    return {
      ...content,
      parts: sanitizedParts
    }
  })
}

/**
 * 读取可读流内容为字符串
 */
async function readStreamToString(stream) {
  return new Promise((resolve, reject) => {
    let result = ''

    try {
      if (typeof stream.setEncoding === 'function') {
        stream.setEncoding('utf8')
      }
    } catch (error) {
      logger.warn('设置流编码失败:', error)
    }

    stream.on('data', (chunk) => {
      result += chunk
    })

    stream.on('end', () => {
      resolve(result)
    })

    stream.on('error', (error) => {
      reject(error)
    })
  })
}

/**
 * 规范化上游 Axios 错误信息
 */
async function normalizeAxiosStreamError(error) {
  const status = error.response?.status
  const statusText = error.response?.statusText
  const responseData = error.response?.data
  let rawBody = null
  let parsedBody = null

  if (responseData) {
    try {
      if (isReadableStream(responseData)) {
        rawBody = await readStreamToString(responseData)
      } else if (Buffer.isBuffer(responseData)) {
        rawBody = responseData.toString('utf8')
      } else if (typeof responseData === 'string') {
        rawBody = responseData
      } else {
        rawBody = JSON.stringify(responseData)
      }
    } catch (streamError) {
      logger.warn('读取 Gemini 上游错误流失败:', streamError)
    }
  }

  if (rawBody) {
    if (typeof rawBody === 'string') {
      try {
        parsedBody = JSON.parse(rawBody)
      } catch (parseError) {
        parsedBody = rawBody
      }
    } else {
      parsedBody = rawBody
    }
  }

  let finalMessage = error.message || 'Internal server error'
  if (parsedBody && typeof parsedBody === 'object') {
    finalMessage = parsedBody.error?.message || parsedBody.message || finalMessage
  } else if (typeof parsedBody === 'string' && parsedBody.trim()) {
    finalMessage = parsedBody.trim()
  }

  return {
    status,
    statusText,
    message: finalMessage,
    parsedBody,
    rawBody
  }
}

/**
 * 解析账户代理配置
 */
function parseProxyConfig(account) {
  let proxyConfig = null
  if (account.proxy) {
    try {
      proxyConfig = typeof account.proxy === 'string' ? JSON.parse(account.proxy) : account.proxy
    } catch (e) {
      logger.warn('Failed to parse proxy configuration:', e)
    }
  }
  return proxyConfig
}

// ============================================================================
// 处理函数 - OpenAI 兼容格式（/messages 端点）
// ============================================================================

/**
 * 处理 OpenAI 兼容格式的消息请求
 */
async function handleMessages(req, res) {
  const startTime = Date.now()
  let abortController = null
  let accountId
  let accountType
  let sessionHash

  try {
    const apiKeyData = req.apiKey

    // 检查权限
    if (!checkPermissions(apiKeyData, 'gemini')) {
      return res.status(403).json({
        error: {
          message: 'This API key does not have permission to access Gemini',
          type: 'permission_denied'
        }
      })
    }

    // 提取请求参数
    const {
      messages,
      model = 'gemini-2.5-flash',
      temperature = 0.7,
      max_tokens = 4096,
      stream = false
    } = req.body

    // 验证必需参数
    if (!messages || !Array.isArray(messages) || messages.length === 0) {
      return res.status(400).json({
        error: {
          message: 'Messages array is required',
          type: 'invalid_request_error'
        }
      })
    }

    // 生成会话哈希用于粘性会话
    sessionHash = generateSessionHash(req)

    // 使用统一调度选择可用的 Gemini 账户（传递请求的模型）
    try {
      const schedulerResult = await unifiedGeminiScheduler.selectAccountForApiKey(
        apiKeyData,
        sessionHash,
        model, // 传递请求的模型进行过滤
        { allowApiAccounts: true } // 允许调度 API 账户
      )
      ;({ accountId, accountType } = schedulerResult)
    } catch (error) {
      logger.error('Failed to select Gemini account:', error)
      return res.status(503).json({
        error: {
          message: error.message || 'No available Gemini accounts',
          type: 'service_unavailable'
        }
      })
    }

    // 判断账户类型：根据 accountType 判断，而非 accountId 前缀
    const isApiAccount = accountType === 'gemini-api'

    // 获取账户详情
    let account
    if (isApiAccount) {
      account = await geminiApiAccountService.getAccount(accountId)
      if (!account) {
        return res.status(503).json({
          error: {
            message: 'Gemini API account not found',
            type: 'service_unavailable'
          }
        })
      }
      logger.info(`Using Gemini API account: ${account.id} for API key: ${apiKeyData.id}`)
      // 标记 API 账户被使用
      await geminiApiAccountService.markAccountUsed(account.id)
    } else {
      account = await geminiAccountService.getAccount(accountId)
      if (!account) {
        return res.status(503).json({
          error: {
            message: 'Gemini OAuth account not found',
            type: 'service_unavailable'
          }
        })
      }
      logger.info(`Using Gemini OAuth account: ${account.id} for API key: ${apiKeyData.id}`)
      // 标记 OAuth 账户被使用
      await geminiAccountService.markAccountUsed(account.id)
    }

    // 创建中止控制器
    abortController = new AbortController()

    // 处理客户端断开连接
    req.on('close', () => {
      if (abortController && !abortController.signal.aborted) {
        logger.info('Client disconnected, aborting Gemini request')
        abortController.abort()
      }
    })

    let geminiResponse

    if (isApiAccount) {
      // API 账户：直接调用 Google Gemini API
      // 转换 OpenAI 格式的 messages 为 Gemini 格式的 contents
      const contents = messages.map((msg) => ({
        role: msg.role === 'assistant' ? 'model' : msg.role,
        parts: [{ text: msg.content }]
      }))

      const requestBody = {
        contents,
        generationConfig: {
          temperature,
          maxOutputTokens: max_tokens,
          topP: 0.95,
          topK: 40
        }
      }

      // 解析代理配置
      const proxyConfig = parseProxyConfig(account)

      const apiUrl = buildGeminiApiUrl(
        account.baseUrl,
        model,
        stream ? 'streamGenerateContent' : 'generateContent',
        account.apiKey,
        { stream }
      )

      const axiosConfig = {
        method: 'POST',
        url: apiUrl,
        data: requestBody,
        headers: {
          'Content-Type': 'application/json',
          'x-api-key': account.apiKey,
          'x-goog-api-key': account.apiKey
        },
        responseType: stream ? 'stream' : 'json',
        signal: abortController.signal
      }

      // 添加代理配置
      if (proxyConfig) {
        axiosConfig.httpsAgent = ProxyHelper.createProxyAgent(proxyConfig)
        axiosConfig.httpAgent = ProxyHelper.createProxyAgent(proxyConfig)
      }

      try {
        const apiResponse = await axios(axiosConfig)
        if (stream) {
          geminiResponse = apiResponse.data
        } else {
          // 转换为 OpenAI 兼容格式
          const geminiData = apiResponse.data
          geminiResponse = {
            id: crypto.randomUUID(),
            object: 'chat.completion',
            created: Math.floor(Date.now() / 1000),
            model,
            choices: [
              {
                index: 0,
                message: {
                  role: 'assistant',
                  content:
                    geminiData.candidates?.[0]?.content?.parts?.[0]?.text || 'No response generated'
                },
                finish_reason: 'stop'
              }
            ],
            usage: {
              prompt_tokens: geminiData.usageMetadata?.promptTokenCount || 0,
              completion_tokens: geminiData.usageMetadata?.candidatesTokenCount || 0,
              total_tokens: geminiData.usageMetadata?.totalTokenCount || 0
            }
          }

          // 记录使用统计
          if (geminiData.usageMetadata) {
            await apiKeyService.recordUsage(
              apiKeyData.id,
              geminiData.usageMetadata.promptTokenCount || 0,
              geminiData.usageMetadata.candidatesTokenCount || 0,
              0,
              0,
              model,
              accountId
            )
          }
        }
      } catch (error) {
        logger.error('Gemini API request failed:', {
          status: error.response?.status,
          statusText: error.response?.statusText,
          data: error.response?.data
        })
        throw error
      }
    } else {
      // OAuth 账户：使用现有的 sendGeminiRequest
      // 智能处理项目ID：优先使用配置的 projectId，降级到临时 tempProjectId
      const effectiveProjectId = account.projectId || account.tempProjectId || null

      geminiResponse = await sendGeminiRequest({
        messages,
        model,
        temperature,
        maxTokens: max_tokens,
        stream,
        accessToken: account.accessToken,
        proxy: account.proxy,
        apiKeyId: apiKeyData.id,
        signal: abortController.signal,
        projectId: effectiveProjectId,
        accountId: account.id
      })
    }

    if (stream) {
      // 设置流式响应头
      res.setHeader('Content-Type', 'text/event-stream')
      res.setHeader('Cache-Control', 'no-cache')
      res.setHeader('Connection', 'keep-alive')
      res.setHeader('X-Accel-Buffering', 'no')

      if (isApiAccount) {
        // API 账户：处理 SSE 流并记录使用统计
        let totalUsage = {
          promptTokenCount: 0,
          candidatesTokenCount: 0,
          totalTokenCount: 0
        }

        geminiResponse.on('data', (chunk) => {
          try {
            const chunkStr = chunk.toString()
            res.write(chunkStr)

            // 尝试从 SSE 流中提取 usage 数据
            const lines = chunkStr.split('\n')
            for (const line of lines) {
              if (line.startsWith('data:')) {
                const data = line.substring(5).trim()
                if (data && data !== '[DONE]') {
                  try {
                    const parsed = JSON.parse(data)
                    if (parsed.usageMetadata || parsed.response?.usageMetadata) {
                      totalUsage = parsed.usageMetadata || parsed.response.usageMetadata
                    }
                  } catch (e) {
                    // 解析失败，忽略
                  }
                }
              }
            }
          } catch (error) {
            logger.error('Error processing stream chunk:', error)
          }
        })

        geminiResponse.on('end', () => {
          res.end()

          // 异步记录使用统计
          if (totalUsage.totalTokenCount > 0) {
            apiKeyService
              .recordUsage(
                apiKeyData.id,
                totalUsage.promptTokenCount || 0,
                totalUsage.candidatesTokenCount || 0,
                0,
                0,
                model,
                accountId
              )
              .then(() => {
                logger.info(
                  `📊 Recorded Gemini API stream usage - Input: ${totalUsage.promptTokenCount}, Output: ${totalUsage.candidatesTokenCount}`
                )
              })
              .catch((error) => {
                logger.error('Failed to record Gemini API usage:', error)
              })
          }
        })

        geminiResponse.on('error', (error) => {
          logger.error('Stream error:', error)
          if (!res.headersSent) {
            res.status(500).json({
              error: {
                message: error.message || 'Stream error',
                type: 'api_error'
              }
            })
          } else {
            res.end()
          }
        })
      } else {
        // OAuth 账户：使用原有的流式传输逻辑
        for await (const chunk of geminiResponse) {
          if (abortController.signal.aborted) {
            break
          }
          res.write(chunk)
        }
        res.end()
      }
    } else {
      // 非流式响应
      res.json(geminiResponse)
    }

    const duration = Date.now() - startTime
    logger.info(`Gemini request completed in ${duration}ms`)
  } catch (error) {
    logger.error('Gemini request error:', error)

    // 处理速率限制
    const errorStatus = error.response?.status || error.status
    if (errorStatus === 429 && accountId) {
      try {
        const rateLimitAccountType = accountType || 'gemini'
        await unifiedGeminiScheduler.markAccountRateLimited(
          accountId,
          rateLimitAccountType,
          sessionHash
        )
        logger.warn(`⚠️ Gemini account ${accountId} rate limited (/messages), marking as limited`)
      } catch (limitError) {
        logger.warn('Failed to mark account as rate limited:', limitError)
      }
    }

    // 返回错误响应
    const status = errorStatus || 500
    const errorResponse = {
      error: error.error || {
        message: error.message || 'Internal server error',
        type: 'api_error'
      }
    }

    res.status(status).json(errorResponse)
  } finally {
    // 清理资源
    if (abortController) {
      abortController = null
    }
  }
  return undefined
}

// ============================================================================
// 处理函数 - 模型列表和详情
// ============================================================================

/**
 * 获取可用模型列表
 */
async function handleModels(req, res) {
  try {
    const apiKeyData = req.apiKey

    // 检查权限
    if (!checkPermissions(apiKeyData, 'gemini')) {
      return res.status(403).json({
        error: {
          message: 'This API key does not have permission to access Gemini',
          type: 'permission_denied'
        }
      })
    }

    // 选择账户获取模型列表（允许 API 账户）
    let account = null
    let isApiAccount = false
    try {
      const accountSelection = await unifiedGeminiScheduler.selectAccountForApiKey(
        apiKeyData,
        null,
        null,
        { allowApiAccounts: true }
      )
      isApiAccount = accountSelection.accountType === 'gemini-api'
      if (isApiAccount) {
        account = await geminiApiAccountService.getAccount(accountSelection.accountId)
      } else {
        account = await geminiAccountService.getAccount(accountSelection.accountId)
      }
    } catch (error) {
      logger.warn('Failed to select Gemini account for models endpoint:', error)
    }

    if (!account) {
      // 返回默认模型列表
      return res.json({
        object: 'list',
        data: [
          {
            id: 'gemini-2.5-flash',
            object: 'model',
            created: Date.now() / 1000,
            owned_by: 'google'
          }
        ]
      })
    }

    // 获取模型列表
    let models
    if (isApiAccount) {
      // API Key 账户：使用 API Key 获取模型列表
      const proxyConfig = parseProxyConfig(account)
      try {
        const apiUrl = buildGeminiApiUrl(account.baseUrl, null, null, account.apiKey, {
          listModels: true
        })
        const axiosConfig = {
          method: 'GET',
          url: apiUrl,
          headers: { 'Content-Type': 'application/json' }
        }
        if (proxyConfig) {
          axiosConfig.httpsAgent = ProxyHelper.createProxyAgent(proxyConfig)
          axiosConfig.httpAgent = ProxyHelper.createProxyAgent(proxyConfig)
        }
        const response = await axios(axiosConfig)
        models = (response.data.models || []).map((m) => ({
          id: m.name?.replace('models/', '') || m.name,
          object: 'model',
          created: Date.now() / 1000,
          owned_by: 'google'
        }))
      } catch (error) {
        logger.warn('Failed to fetch models from Gemini API:', error.message)
        // 返回默认模型列表
        models = [
          {
            id: 'gemini-2.5-flash',
            object: 'model',
            created: Date.now() / 1000,
            owned_by: 'google'
          }
        ]
      }
    } else {
      // OAuth 账户：使用 OAuth token 获取模型列表
      models = await getAvailableModels(account.accessToken, account.proxy)
    }

    res.json({
      object: 'list',
      data: models
    })
  } catch (error) {
    logger.error('Failed to get Gemini models:', error)
    res.status(500).json({
      error: {
        message: 'Failed to retrieve models',
        type: 'api_error'
      }
    })
  }
  return undefined
}

/**
 * 获取模型详情（标准 Gemini API 格式）
 */
function handleModelDetails(req, res) {
  const { modelName } = req.params
  const version = req.path.includes('v1beta') ? 'v1beta' : 'v1'
  logger.info(`Standard Gemini API model details request (${version}): ${modelName}`)

  res.json({
    name: `models/${modelName}`,
    version: '001',
    displayName: modelName,
    description: `Gemini model: ${modelName}`,
    inputTokenLimit: 1048576,
    outputTokenLimit: 8192,
    supportedGenerationMethods: ['generateContent', 'streamGenerateContent', 'countTokens'],
    temperature: 1.0,
    topP: 0.95,
    topK: 40
  })
}

// ============================================================================
// 处理函数 - 使用统计和 API Key 信息
// ============================================================================

/**
 * 获取使用情况统计
 */
async function handleUsage(req, res) {
  try {
    const { usage } = req.apiKey

    res.json({
      object: 'usage',
      total_tokens: usage.total.tokens,
      total_requests: usage.total.requests,
      daily_tokens: usage.daily.tokens,
      daily_requests: usage.daily.requests,
      monthly_tokens: usage.monthly.tokens,
      monthly_requests: usage.monthly.requests
    })
  } catch (error) {
    logger.error('Failed to get usage stats:', error)
    res.status(500).json({
      error: {
        message: 'Failed to retrieve usage statistics',
        type: 'api_error'
      }
    })
  }
}

/**
 * 获取 API Key 信息
 */
async function handleKeyInfo(req, res) {
  try {
    const keyData = req.apiKey

    res.json({
      id: keyData.id,
      name: keyData.name,
      permissions: keyData.permissions || 'all',
      token_limit: keyData.tokenLimit,
      tokens_used: keyData.usage.total.tokens,
      tokens_remaining:
        keyData.tokenLimit > 0
          ? Math.max(0, keyData.tokenLimit - keyData.usage.total.tokens)
          : null,
      rate_limit: {
        window: keyData.rateLimitWindow,
        requests: keyData.rateLimitRequests
      },
      concurrency_limit: keyData.concurrencyLimit,
      model_restrictions: {
        enabled: keyData.enableModelRestriction,
        models: keyData.restrictedModels
      }
    })
  } catch (error) {
    logger.error('Failed to get key info:', error)
    res.status(500).json({
      error: {
        message: 'Failed to retrieve API key information',
        type: 'api_error'
      }
    })
  }
}

// ============================================================================
// 处理函数 - v1internal 格式（Gemini CLI 内部格式）
// ============================================================================

/**
 * 简单端点处理函数工厂（用于直接转发的端点）
 */
function handleSimpleEndpoint(apiMethod) {
  return async (req, res) => {
    try {
      if (!ensureGeminiPermission(req, res)) {
        return undefined
      }

      const sessionHash = sessionHelper.generateSessionHash(req.body)

      // 从路径参数或请求体中获取模型名
      const requestedModel = req.body.model || req.params.modelName || 'gemini-2.5-flash'
      const schedulerResult = await unifiedGeminiScheduler.selectAccountForApiKey(
        req.apiKey,
        sessionHash,
        requestedModel
      )
      const { accountId, accountType } = schedulerResult

      // v1internal 路由只支持 OAuth 账户，不支持 API Key 账户
      if (accountType === 'gemini-api') {
        logger.error(
          `❌ v1internal routes do not support Gemini API accounts. Account: ${accountId}`
        )
        return res.status(400).json({
          error: {
            message:
              'This endpoint only supports Gemini OAuth accounts. Gemini API Key accounts are not compatible with v1internal format.',
            type: 'invalid_account_type'
          }
        })
      }

      const account = await geminiAccountService.getAccount(accountId)
      if (!account) {
        return res.status(404).json({
          error: {
            message: 'Gemini account not found',
            type: 'account_not_found'
          }
        })
      }
      const { accessToken, refreshToken } = account

      const version = req.path.includes('v1beta') ? 'v1beta' : 'v1internal'
      logger.info(`${apiMethod} request (${version})`, {
        apiKeyId: req.apiKey?.id || 'unknown',
        requestBody: req.body
      })

      // 解析账户的代理配置
      const proxyConfig = parseProxyConfig(account)

      const client = await geminiAccountService.getOauthClient(
        accessToken,
        refreshToken,
        proxyConfig
      )

      // 直接转发请求体，不做特殊处理
      const response = await geminiAccountService.forwardToCodeAssist(
        client,
        apiMethod,
        req.body,
        proxyConfig
      )

      res.json(response)
    } catch (error) {
      const version = req.path.includes('v1beta') ? 'v1beta' : 'v1internal'
      logger.error(`Error in ${apiMethod} endpoint (${version})`, { error: error.message })
      res.status(500).json({
        error: 'Internal server error',
        message: error.message
      })
    }
  }
}

/**
 * 处理 loadCodeAssist 请求
 */
async function handleLoadCodeAssist(req, res) {
  try {
    if (!ensureGeminiPermission(req, res)) {
      return undefined
    }

    const sessionHash = sessionHelper.generateSessionHash(req.body)

    // 从路径参数或请求体中获取模型名
    const requestedModel = req.body.model || req.params.modelName || 'gemini-2.5-flash'
    const schedulerResult = await unifiedGeminiScheduler.selectAccountForApiKey(
      req.apiKey,
      sessionHash,
      requestedModel
    )
    const { accountId, accountType } = schedulerResult

    // v1internal 路由只支持 OAuth 账户，不支持 API Key 账户
    if (accountType === 'gemini-api') {
      logger.error(`❌ v1internal routes do not support Gemini API accounts. Account: ${accountId}`)
      return res.status(400).json({
        error: {
          message:
            'This endpoint only supports Gemini OAuth accounts. Gemini API Key accounts are not compatible with v1internal format.',
          type: 'invalid_account_type'
        }
      })
    }

    const account = await geminiAccountService.getAccount(accountId)
    if (!account) {
      return res.status(404).json({
        error: {
          message: 'Gemini account not found',
          type: 'account_not_found'
        }
      })
    }
    const { accessToken, refreshToken, projectId } = account

    const { metadata, cloudaicompanionProject } = req.body

    const version = req.path.includes('v1beta') ? 'v1beta' : 'v1internal'
    logger.info(`LoadCodeAssist request (${version})`, {
      metadata: metadata || {},
      requestedProject: cloudaicompanionProject || null,
      accountProject: projectId || null,
      apiKeyId: req.apiKey?.id || 'unknown'
    })

    // 解析账户的代理配置
    const proxyConfig = parseProxyConfig(account)

    const client = await geminiAccountService.getOauthClient(accessToken, refreshToken, proxyConfig)

    // 智能处理项目ID
    const effectiveProjectId = projectId || cloudaicompanionProject || null

    logger.info('📋 loadCodeAssist项目ID处理逻辑', {
      accountProjectId: projectId,
      requestProjectId: cloudaicompanionProject,
      effectiveProjectId,
      decision: projectId
        ? '使用账户配置'
        : cloudaicompanionProject
          ? '使用请求参数'
          : '不使用项目ID'
    })

    const response = await geminiAccountService.loadCodeAssist(
      client,
      effectiveProjectId,
      proxyConfig
    )

    // 如果响应中包含 cloudaicompanionProject，保存到账户作为临时项目 ID
    if (response.cloudaicompanionProject && !account.projectId) {
      await geminiAccountService.updateTempProjectId(accountId, response.cloudaicompanionProject)
      logger.info(
        `📋 Cached temporary projectId from loadCodeAssist: ${response.cloudaicompanionProject}`
      )
    }

    res.json(response)
  } catch (error) {
    const version = req.path.includes('v1beta') ? 'v1beta' : 'v1internal'
    logger.error(`Error in loadCodeAssist endpoint (${version})`, { error: error.message })
    res.status(500).json({
      error: 'Internal server error',
      message: error.message
    })
  }
}

/**
 * 处理 onboardUser 请求
 */
async function handleOnboardUser(req, res) {
  try {
    if (!ensureGeminiPermission(req, res)) {
      return undefined
    }

    // 提取请求参数
    const { tierId, cloudaicompanionProject, metadata } = req.body
    const sessionHash = sessionHelper.generateSessionHash(req.body)

    // 从路径参数或请求体中获取模型名
    const requestedModel = req.body.model || req.params.modelName || 'gemini-2.5-flash'
    const schedulerResult = await unifiedGeminiScheduler.selectAccountForApiKey(
      req.apiKey,
      sessionHash,
      requestedModel
    )
    const { accountId, accountType } = schedulerResult

    // v1internal 路由只支持 OAuth 账户，不支持 API Key 账户
    if (accountType === 'gemini-api') {
      logger.error(`❌ v1internal routes do not support Gemini API accounts. Account: ${accountId}`)
      return res.status(400).json({
        error: {
          message:
            'This endpoint only supports Gemini OAuth accounts. Gemini API Key accounts are not compatible with v1internal format.',
          type: 'invalid_account_type'
        }
      })
    }

    const account = await geminiAccountService.getAccount(accountId)
    if (!account) {
      return res.status(404).json({
        error: {
          message: 'Gemini account not found',
          type: 'account_not_found'
        }
      })
    }
    const { accessToken, refreshToken, projectId } = account

    const version = req.path.includes('v1beta') ? 'v1beta' : 'v1internal'
    logger.info(`OnboardUser request (${version})`, {
      tierId: tierId || 'not provided',
      requestedProject: cloudaicompanionProject || null,
      accountProject: projectId || null,
      metadata: metadata || {},
      apiKeyId: req.apiKey?.id || 'unknown'
    })

    // 解析账户的代理配置
    const proxyConfig = parseProxyConfig(account)

    const client = await geminiAccountService.getOauthClient(accessToken, refreshToken, proxyConfig)

    // 智能处理项目ID
    const effectiveProjectId = projectId || cloudaicompanionProject || null

    logger.info('📋 onboardUser项目ID处理逻辑', {
      accountProjectId: projectId,
      requestProjectId: cloudaicompanionProject,
      effectiveProjectId,
      decision: projectId
        ? '使用账户配置'
        : cloudaicompanionProject
          ? '使用请求参数'
          : '不使用项目ID'
    })

    // 如果提供了 tierId，直接调用 onboardUser
    if (tierId) {
      const response = await geminiAccountService.onboardUser(
        client,
        tierId,
        effectiveProjectId,
        metadata,
        proxyConfig
      )

      res.json(response)
    } else {
      // 否则执行完整的 setupUser 流程
      const response = await geminiAccountService.setupUser(
        client,
        effectiveProjectId,
        metadata,
        proxyConfig
      )

      res.json(response)
    }
  } catch (error) {
    const version = req.path.includes('v1beta') ? 'v1beta' : 'v1internal'
    logger.error(`Error in onboardUser endpoint (${version})`, { error: error.message })
    res.status(500).json({
      error: 'Internal server error',
      message: error.message
    })
  }
}

/**
 * 处理 countTokens 请求
 */
async function handleCountTokens(req, res) {
  try {
    if (!ensureGeminiPermission(req, res)) {
      return undefined
    }

    // 处理请求体结构，支持直接 contents 或 request.contents
    const requestData = req.body.request || req.body
    const { contents } = requestData
    // 从路径参数或请求体中获取模型名
    const model = requestData.model || req.params.modelName || 'gemini-2.5-flash'
    const sessionHash = sessionHelper.generateSessionHash(req.body)

    // 验证必需参数
    if (!contents || !Array.isArray(contents)) {
      return res.status(400).json({
        error: {
          message: 'Contents array is required',
          type: 'invalid_request_error'
        }
      })
    }

    // 使用统一调度选择账号（允许 API 账户）
    const schedulerResult = await unifiedGeminiScheduler.selectAccountForApiKey(
      req.apiKey,
      sessionHash,
      model,
      { allowApiAccounts: true }
    )
    const { accountId, accountType } = schedulerResult
    const isApiAccount = accountType === 'gemini-api'

    let account
    if (isApiAccount) {
      account = await geminiApiAccountService.getAccount(accountId)
    } else {
      account = await geminiAccountService.getAccount(accountId)
    }

    if (!account) {
      return res.status(404).json({
        error: {
          message: `${isApiAccount ? 'Gemini API' : 'Gemini'} account not found`,
          type: 'account_not_found'
        }
      })
    }

    const version = req.path.includes('v1beta') ? 'v1beta' : 'v1'
    logger.info(
      `CountTokens request (${version}) - ${isApiAccount ? 'API Key' : 'OAuth'} Account`,
      {
        model,
        contentsLength: contents.length,
        accountId,
        apiKeyId: req.apiKey?.id || 'unknown'
      }
    )

    // 解析账户的代理配置
    const proxyConfig = parseProxyConfig(account)

    let response
    if (isApiAccount) {
      // API Key 账户：直接使用 API Key 请求
      const modelName = model.startsWith('models/') ? model.replace('models/', '') : model
      const apiUrl = buildGeminiApiUrl(account.baseUrl, modelName, 'countTokens', account.apiKey)

      const axiosConfig = {
        method: 'POST',
        url: apiUrl,
        data: { contents },
        headers: { 'Content-Type': 'application/json' }
      }

      if (proxyConfig) {
        axiosConfig.httpsAgent = ProxyHelper.createProxyAgent(proxyConfig)
        axiosConfig.httpAgent = ProxyHelper.createProxyAgent(proxyConfig)
      }

      try {
        const apiResponse = await axios(axiosConfig)
        response = {
          totalTokens: apiResponse.data.totalTokens || 0,
          totalBillableCharacters: apiResponse.data.totalBillableCharacters || 0,
          ...apiResponse.data
        }
      } catch (error) {
        logger.error('Gemini API countTokens request failed:', {
          status: error.response?.status,
          data: error.response?.data
        })
        throw error
      }
    } else {
      // OAuth 账户
      const { accessToken, refreshToken } = account
      const client = await geminiAccountService.getOauthClient(
        accessToken,
        refreshToken,
        proxyConfig
      )
      response = await geminiAccountService.countTokens(client, contents, model, proxyConfig)
    }

    res.json(response)
  } catch (error) {
    const version = req.path.includes('v1beta') ? 'v1beta' : 'v1'
    logger.error(`Error in countTokens endpoint (${version})`, { error: error.message })
    res.status(500).json({
      error: {
        message: error.message || 'Internal server error',
        type: 'api_error'
      }
    })
  }
  return undefined
}

/**
 * 处理 generateContent 请求（v1internal 格式）
 */
async function handleGenerateContent(req, res) {
  try {
    if (!ensureGeminiPermission(req, res)) {
      return undefined
    }

    const { project, user_prompt_id, request: requestData } = req.body
    // 从路径参数或请求体中获取模型名
    const model = req.body.model || req.params.modelName || 'gemini-2.5-flash'
    const sessionHash = sessionHelper.generateSessionHash(req.body)

    // 处理不同格式的请求
    let actualRequestData = requestData
    if (!requestData) {
      if (req.body.messages) {
        // 这是 OpenAI 格式的请求，构建 Gemini 格式的 request 对象
        actualRequestData = {
          contents: req.body.messages.map((msg) => ({
            role: msg.role === 'assistant' ? 'model' : msg.role,
            parts: [{ text: msg.content }]
          })),
          generationConfig: {
            temperature: req.body.temperature !== undefined ? req.body.temperature : 0.7,
            maxOutputTokens: req.body.max_tokens !== undefined ? req.body.max_tokens : 4096,
            topP: req.body.top_p !== undefined ? req.body.top_p : 0.95,
            topK: req.body.top_k !== undefined ? req.body.top_k : 40
          }
        }
      } else if (req.body.contents) {
        // 直接的 Gemini 格式请求（没有 request 包装）
        actualRequestData = req.body
      }
    }

    // 验证必需参数
    if (!actualRequestData || !actualRequestData.contents) {
      return res.status(400).json({
        error: {
          message: 'Request contents are required',
          type: 'invalid_request_error'
        }
      })
    }

    // 使用统一调度选择账号（v1internal 不允许 API 账户）
    const schedulerResult = await unifiedGeminiScheduler.selectAccountForApiKey(
      req.apiKey,
      sessionHash,
      model
    )
    const { accountId, accountType } = schedulerResult

    // v1internal 路由只支持 OAuth 账户，不支持 API Key 账户
    if (accountType === 'gemini-api') {
      logger.error(`❌ v1internal routes do not support Gemini API accounts. Account: ${accountId}`)
      return res.status(400).json({
        error: {
          message:
            'This endpoint only supports Gemini OAuth accounts. Gemini API Key accounts are not compatible with v1internal format.',
          type: 'invalid_account_type'
        }
      })
    }

    const account = await geminiAccountService.getAccount(accountId)
    if (!account) {
      logger.error(`❌ Gemini account not found: ${accountId}`)
      return res.status(404).json({
        error: {
          message: 'Gemini account not found',
          type: 'account_not_found'
        }
      })
    }

    const { accessToken, refreshToken } = account

    const version = req.path.includes('v1beta') ? 'v1beta' : 'v1internal'
    logger.info(`GenerateContent request (${version})`, {
      model,
      userPromptId: user_prompt_id,
      projectId: project || account.projectId,
      apiKeyId: req.apiKey?.id || 'unknown'
    })

    // 解析账户的代理配置
    const proxyConfig = parseProxyConfig(account)

    const client = await geminiAccountService.getOauthClient(accessToken, refreshToken, proxyConfig)

    // 智能处理项目ID：优先使用配置的 projectId，降级到临时 tempProjectId
    let effectiveProjectId = account.projectId || account.tempProjectId || null

    // 如果没有任何项目ID，尝试调用 loadCodeAssist 获取
    if (!effectiveProjectId) {
      try {
        logger.info('📋 No projectId available, attempting to fetch from loadCodeAssist...')
        const loadResponse = await geminiAccountService.loadCodeAssist(client, null, proxyConfig)

        if (loadResponse.cloudaicompanionProject) {
          effectiveProjectId = loadResponse.cloudaicompanionProject
          // 保存临时项目ID
          await geminiAccountService.updateTempProjectId(accountId, effectiveProjectId)
          logger.info(`📋 Fetched and cached temporary projectId: ${effectiveProjectId}`)
        }
      } catch (loadError) {
        logger.warn('Failed to fetch projectId from loadCodeAssist:', loadError.message)
      }
    }

    // 如果还是没有项目ID，返回错误
    if (!effectiveProjectId) {
      return res.status(403).json({
        error: {
          message:
            'This account requires a project ID to be configured. Please configure a project ID in the account settings.',
          type: 'configuration_required'
        }
      })
    }

    logger.info('📋 项目ID处理逻辑', {
      accountProjectId: account.projectId,
      accountTempProjectId: account.tempProjectId,
      effectiveProjectId,
      decision: account.projectId
        ? '使用账户配置'
        : account.tempProjectId
          ? '使用临时项目ID'
          : '从loadCodeAssist获取'
    })

    const response = await geminiAccountService.generateContent(
      client,
      { model, request: actualRequestData },
      user_prompt_id,
      effectiveProjectId,
      req.apiKey?.id,
      proxyConfig
    )

    // 记录使用统计
    if (response?.response?.usageMetadata) {
      try {
        const usage = response.response.usageMetadata
        await apiKeyService.recordUsage(
          req.apiKey.id,
          usage.promptTokenCount || 0,
          usage.candidatesTokenCount || 0,
          0,
          0,
          model,
          account.id
        )
        logger.info(
          `📊 Recorded Gemini usage - Input: ${usage.promptTokenCount}, Output: ${usage.candidatesTokenCount}, Total: ${usage.totalTokenCount}`
        )

        await applyRateLimitTracking(
          req,
          {
            inputTokens: usage.promptTokenCount || 0,
            outputTokens: usage.candidatesTokenCount || 0,
            cacheCreateTokens: 0,
            cacheReadTokens: 0
          },
          model,
          'gemini-non-stream'
        )
      } catch (error) {
        logger.error('Failed to record Gemini usage:', error)
      }
    }

    res.json(version === 'v1beta' ? response.response : response)
  } catch (error) {
    const version = req.path.includes('v1beta') ? 'v1beta' : 'v1internal'
    logger.error(`Error in generateContent endpoint (${version})`, {
      message: error.message,
      status: error.response?.status,
      statusText: error.response?.statusText,
      responseData: error.response?.data,
      requestUrl: error.config?.url,
      requestMethod: error.config?.method,
      stack: error.stack
    })
    res.status(500).json({
      error: {
        message: error.message || 'Internal server error',
        type: 'api_error'
      }
    })
  }
  return undefined
}

/**
 * 处理 streamGenerateContent 请求（v1internal 格式）
 */
async function handleStreamGenerateContent(req, res) {
  let abortController = null

  try {
    if (!ensureGeminiPermission(req, res)) {
      return undefined
    }

    const { project, user_prompt_id, request: requestData } = req.body
    // 从路径参数或请求体中获取模型名
    const model = req.body.model || req.params.modelName || 'gemini-2.5-flash'
    const sessionHash = sessionHelper.generateSessionHash(req.body)

    // 处理不同格式的请求
    let actualRequestData = requestData
    if (!requestData) {
      if (req.body.messages) {
        // 这是 OpenAI 格式的请求，构建 Gemini 格式的 request 对象
        actualRequestData = {
          contents: req.body.messages.map((msg) => ({
            role: msg.role === 'assistant' ? 'model' : msg.role,
            parts: [{ text: msg.content }]
          })),
          generationConfig: {
            temperature: req.body.temperature !== undefined ? req.body.temperature : 0.7,
            maxOutputTokens: req.body.max_tokens !== undefined ? req.body.max_tokens : 4096,
            topP: req.body.top_p !== undefined ? req.body.top_p : 0.95,
            topK: req.body.top_k !== undefined ? req.body.top_k : 40
          }
        }
      } else if (req.body.contents) {
        // 直接的 Gemini 格式请求（没有 request 包装）
        actualRequestData = req.body
      }
    }

    // 验证必需参数
    if (!actualRequestData || !actualRequestData.contents) {
      return res.status(400).json({
        error: {
          message: 'Request contents are required',
          type: 'invalid_request_error'
        }
      })
    }

    // 使用统一调度选择账号（v1internal 不允许 API 账户）
    const schedulerResult = await unifiedGeminiScheduler.selectAccountForApiKey(
      req.apiKey,
      sessionHash,
      model
    )
    const { accountId, accountType } = schedulerResult

    // v1internal 路由只支持 OAuth 账户，不支持 API Key 账户
    if (accountType === 'gemini-api') {
      logger.error(`❌ v1internal routes do not support Gemini API accounts. Account: ${accountId}`)
      return res.status(400).json({
        error: {
          message:
            'This endpoint only supports Gemini OAuth accounts. Gemini API Key accounts are not compatible with v1internal format.',
          type: 'invalid_account_type'
        }
      })
    }

    const account = await geminiAccountService.getAccount(accountId)
    if (!account) {
      logger.error(`❌ Gemini account not found: ${accountId}`)
      return res.status(404).json({
        error: {
          message: 'Gemini account not found',
          type: 'account_not_found'
        }
      })
    }

    const { accessToken, refreshToken } = account

    const version = req.path.includes('v1beta') ? 'v1beta' : 'v1internal'
    logger.info(`StreamGenerateContent request (${version})`, {
      model,
      userPromptId: user_prompt_id,
      projectId: project || account.projectId,
      apiKeyId: req.apiKey?.id || 'unknown'
    })

    // 创建中止控制器
    abortController = new AbortController()

    // 处理客户端断开连接
    req.on('close', () => {
      if (abortController && !abortController.signal.aborted) {
        logger.info('Client disconnected, aborting stream request')
        abortController.abort()
      }
    })

    // 解析账户的代理配置
    const proxyConfig = parseProxyConfig(account)

    const client = await geminiAccountService.getOauthClient(accessToken, refreshToken, proxyConfig)

    // 智能处理项目ID：优先使用配置的 projectId，降级到临时 tempProjectId
    let effectiveProjectId = account.projectId || account.tempProjectId || null

    // 如果没有任何项目ID，尝试调用 loadCodeAssist 获取
    if (!effectiveProjectId) {
      try {
        logger.info('📋 No projectId available, attempting to fetch from loadCodeAssist...')
        const loadResponse = await geminiAccountService.loadCodeAssist(client, null, proxyConfig)

        if (loadResponse.cloudaicompanionProject) {
          effectiveProjectId = loadResponse.cloudaicompanionProject
          // 保存临时项目ID
          await geminiAccountService.updateTempProjectId(accountId, effectiveProjectId)
          logger.info(`📋 Fetched and cached temporary projectId: ${effectiveProjectId}`)
        }
      } catch (loadError) {
        logger.warn('Failed to fetch projectId from loadCodeAssist:', loadError.message)
      }
    }

    // 如果还是没有项目ID，返回错误
    if (!effectiveProjectId) {
      return res.status(403).json({
        error: {
          message:
            'This account requires a project ID to be configured. Please configure a project ID in the account settings.',
          type: 'configuration_required'
        }
      })
    }

    logger.info('📋 流式请求项目ID处理逻辑', {
      accountProjectId: account.projectId,
      accountTempProjectId: account.tempProjectId,
      effectiveProjectId,
      decision: account.projectId
        ? '使用账户配置'
        : account.tempProjectId
          ? '使用临时项目ID'
          : '从loadCodeAssist获取'
    })

    const streamResponse = await geminiAccountService.generateContentStream(
      client,
      { model, request: actualRequestData },
      user_prompt_id,
      effectiveProjectId,
      req.apiKey?.id,
      abortController.signal,
      proxyConfig
    )

    // 设置 SSE 响应头
    res.setHeader('Content-Type', 'text/event-stream')
    res.setHeader('Cache-Control', 'no-cache')
    res.setHeader('Connection', 'keep-alive')
    res.setHeader('X-Accel-Buffering', 'no')

    // 处理流式响应并捕获usage数据
    let streamBuffer = ''
    let totalUsage = {
      promptTokenCount: 0,
      candidatesTokenCount: 0,
      totalTokenCount: 0
    }
    let usageReported = false

    // SSE 心跳机制
    let heartbeatTimer = null
    let lastDataTime = Date.now()
    const HEARTBEAT_INTERVAL = 15000

    const sendHeartbeat = () => {
      const timeSinceLastData = Date.now() - lastDataTime
      if (timeSinceLastData >= HEARTBEAT_INTERVAL && !res.destroyed) {
        res.write('\n')
        logger.info(`💓 Sent SSE keepalive (gap: ${(timeSinceLastData / 1000).toFixed(1)}s)`)
      }
    }

    heartbeatTimer = setInterval(sendHeartbeat, HEARTBEAT_INTERVAL)

    streamResponse.on('data', (chunk) => {
      try {
        lastDataTime = Date.now()

        // 立即转发原始数据
        if (!res.destroyed) {
          res.write(chunk)
        }

        // 异步提取 usage 数据
        setImmediate(() => {
          try {
            const chunkStr = chunk.toString()
            if (!chunkStr.trim() || !chunkStr.includes('usageMetadata')) {
              return
            }

            streamBuffer += chunkStr
            const lines = streamBuffer.split('\n')
            streamBuffer = lines.pop() || ''

            for (const line of lines) {
              if (!line.trim() || !line.includes('usageMetadata')) {
                continue
              }

              try {
                const parsed = parseSSELine(line)
                if (parsed.type === 'data' && parsed.data.response?.usageMetadata) {
                  totalUsage = parsed.data.response.usageMetadata
                  logger.debug('📊 Captured Gemini usage data:', totalUsage)
                }
              } catch (parseError) {
                logger.warn('⚠️ Failed to parse usage line:', parseError.message)
              }
            }
          } catch (error) {
            logger.warn('⚠️ Error extracting usage data:', error.message)
          }
        })
      } catch (error) {
        logger.error('Error processing stream chunk:', error)
      }
    })

    streamResponse.on('end', () => {
      logger.info('Stream completed successfully')

      if (heartbeatTimer) {
        clearInterval(heartbeatTimer)
        heartbeatTimer = null
      }

      res.end()

      // 异步记录使用统计
      if (!usageReported && totalUsage.totalTokenCount > 0) {
        Promise.all([
          apiKeyService.recordUsage(
            req.apiKey.id,
            totalUsage.promptTokenCount || 0,
            totalUsage.candidatesTokenCount || 0,
            0,
            0,
            model,
            account.id
          ),
          applyRateLimitTracking(
            req,
            {
              inputTokens: totalUsage.promptTokenCount || 0,
              outputTokens: totalUsage.candidatesTokenCount || 0,
              cacheCreateTokens: 0,
              cacheReadTokens: 0
            },
            model,
            'gemini-stream'
          )
        ])
          .then(() => {
            logger.info(
              `📊 Recorded Gemini stream usage - Input: ${totalUsage.promptTokenCount}, Output: ${totalUsage.candidatesTokenCount}, Total: ${totalUsage.totalTokenCount}`
            )
            usageReported = true
          })
          .catch((error) => {
            logger.error('Failed to record Gemini usage:', error)
          })
      }
    })

    streamResponse.on('error', (error) => {
      logger.error('Stream error:', error)

      if (heartbeatTimer) {
        clearInterval(heartbeatTimer)
        heartbeatTimer = null
      }

      if (!res.headersSent) {
        res.status(500).json({
          error: {
            message: error.message || 'Stream error',
            type: 'api_error'
          }
        })
      } else {
        if (!res.destroyed) {
          try {
            res.write(
              `data: ${JSON.stringify({
                error: {
                  message: error.message || 'Stream error',
                  type: 'stream_error',
                  code: error.code
                }
              })}\n\n`
            )
            res.write('data: [DONE]\n\n')
          } catch (writeError) {
            logger.error('Error sending error event:', writeError)
          }
        }
        res.end()
      }
    })
  } catch (error) {
    const version = req.path.includes('v1beta') ? 'v1beta' : 'v1internal'
    logger.error(`Error in streamGenerateContent endpoint (${version})`, {
      message: error.message,
      status: error.response?.status,
      statusText: error.response?.statusText,
      responseData: error.response?.data,
      requestUrl: error.config?.url,
      requestMethod: error.config?.method,
      stack: error.stack
    })

    if (!res.headersSent) {
      res.status(500).json({
        error: {
          message: error.message || 'Internal server error',
          type: 'api_error'
        }
      })
    }
  } finally {
    if (abortController) {
      abortController = null
    }
  }
  return undefined
}

// ============================================================================
// 处理函数 - 标准 Gemini API 格式（/v1beta/models/:model:generateContent 等）
// ============================================================================

/**
 * 处理标准 Gemini API 格式的 generateContent（支持 OAuth 和 API 账户）
 */
async function handleStandardGenerateContent(req, res) {
  let account = null
  let sessionHash = null
  let accountId = null
  let isApiAccount = false

  try {
    if (!ensureGeminiPermission(req, res)) {
      return undefined
    }

    // 从路径参数中获取模型名
    const model = req.params.modelName || 'gemini-2.0-flash-exp'
    sessionHash = sessionHelper.generateSessionHash(req.body)

    // 标准 Gemini API 请求体直接包含 contents 等字段
    const { contents, generationConfig, safetySettings, systemInstruction, tools, toolConfig } =
      req.body

    // 验证必需参数
    if (!contents || !Array.isArray(contents) || contents.length === 0) {
      return res.status(400).json({
        error: {
          message: 'Contents array is required',
          type: 'invalid_request_error'
        }
      })
    }

    // 构建内部 API 需要的请求格式
    const actualRequestData = {
      contents,
      generationConfig: generationConfig || {
        temperature: 0.7,
        maxOutputTokens: 4096,
        topP: 0.95,
        topK: 40
      }
    }

    // 只有在 safetySettings 存在且非空时才添加
    if (safetySettings && safetySettings.length > 0) {
      actualRequestData.safetySettings = safetySettings
    }

    // 添加工具配置
    if (tools) {
      actualRequestData.tools = tools
    }

    if (toolConfig) {
      actualRequestData.toolConfig = toolConfig
    }

    // 处理 system instruction
    if (systemInstruction) {
      if (typeof systemInstruction === 'string' && systemInstruction.trim()) {
        actualRequestData.systemInstruction = {
          role: 'user',
          parts: [{ text: systemInstruction }]
        }
      } else if (systemInstruction.parts && systemInstruction.parts.length > 0) {
        const hasContent = systemInstruction.parts.some(
          (part) => part.text && part.text.trim() !== ''
        )
        if (hasContent) {
          actualRequestData.systemInstruction = {
            role: 'user',
            parts: systemInstruction.parts
          }
        }
      }
    }

    // 使用统一调度选择账号
    const schedulerResult = await unifiedGeminiScheduler.selectAccountForApiKey(
      req.apiKey,
      sessionHash,
      model,
      { allowApiAccounts: true }
    )
    ;({ accountId } = schedulerResult)
    const { accountType } = schedulerResult

    isApiAccount = accountType === 'gemini-api'
    const actualAccountId = accountId

    const version = req.path.includes('v1beta') ? 'v1beta' : 'v1'

    if (isApiAccount) {
      account = await geminiApiAccountService.getAccount(actualAccountId)
      if (!account) {
        return res.status(404).json({
          error: {
            message: 'Gemini API account not found',
            type: 'account_not_found'
          }
        })
      }

      // API Key 账户：清理 functionResponse 中标准 Gemini API 不支持的字段（如 id）
      actualRequestData.contents = sanitizeFunctionResponsesForApiKey(actualRequestData.contents)

      logger.info(`Standard Gemini API generateContent request (${version}) - API Key Account`, {
        model,
        accountId: actualAccountId,
        apiKeyId: req.apiKey?.id || 'unknown'
      })
    } else {
      account = await geminiAccountService.getAccount(actualAccountId)

      logger.info(`Standard Gemini API generateContent request (${version}) - OAuth Account`, {
        model,
        projectId: account.projectId,
        apiKeyId: req.apiKey?.id || 'unknown'
      })
    }

    // 解析账户的代理配置
    const proxyConfig = parseProxyConfig(account)

    let response

    if (isApiAccount) {
      // Gemini API 账户：直接使用 API Key 请求
      const apiUrl = buildGeminiApiUrl(account.baseUrl, model, 'generateContent', account.apiKey)

      const axiosConfig = {
        method: 'POST',
        url: apiUrl,
        data: actualRequestData,
        headers: {
          'Content-Type': 'application/json'
        }
      }

      if (proxyConfig) {
        axiosConfig.httpsAgent = ProxyHelper.createProxyAgent(proxyConfig)
        axiosConfig.httpAgent = ProxyHelper.createProxyAgent(proxyConfig)
      }

      try {
        const apiResponse = await axios(axiosConfig)
        response = { response: apiResponse.data }
      } catch (error) {
        logger.error('Gemini API request failed:', {
          status: error.response?.status,
          statusText: error.response?.statusText,
          data: error.response?.data
        })
        throw error
      }
    } else {
      // OAuth 账户
      const { accessToken, refreshToken } = account
      const client = await geminiAccountService.getOauthClient(
        accessToken,
        refreshToken,
        proxyConfig
      )

      let effectiveProjectId = account.projectId || account.tempProjectId || null

      if (!effectiveProjectId) {
        try {
          logger.info('📋 No projectId available, attempting to fetch from loadCodeAssist...')
          const loadResponse = await geminiAccountService.loadCodeAssist(client, null, proxyConfig)

          if (loadResponse.cloudaicompanionProject) {
            effectiveProjectId = loadResponse.cloudaicompanionProject
            await geminiAccountService.updateTempProjectId(actualAccountId, effectiveProjectId)
            logger.info(`📋 Fetched and cached temporary projectId: ${effectiveProjectId}`)
          }
        } catch (loadError) {
          logger.warn('Failed to fetch projectId from loadCodeAssist:', loadError.message)
        }
      }

      if (!effectiveProjectId) {
        return res.status(403).json({
          error: {
            message:
              'This account requires a project ID to be configured. Please configure a project ID in the account settings.',
            type: 'configuration_required'
          }
        })
      }

      logger.info('📋 Standard API 项目ID处理逻辑', {
        accountProjectId: account.projectId,
        tempProjectId: account.tempProjectId,
        effectiveProjectId,
        decision: account.projectId
          ? '使用账户配置'
          : account.tempProjectId
            ? '使用临时项目ID'
            : '从loadCodeAssist获取'
      })

      const userPromptId = `${crypto.randomUUID()}########0`

      response = await geminiAccountService.generateContent(
        client,
        { model, request: actualRequestData },
        userPromptId,
        effectiveProjectId,
        req.apiKey?.id,
        proxyConfig
      )
    }

    // 记录使用统计
    if (response?.response?.usageMetadata) {
      try {
        const usage = response.response.usageMetadata
        await apiKeyService.recordUsage(
          req.apiKey.id,
          usage.promptTokenCount || 0,
          usage.candidatesTokenCount || 0,
          0,
          0,
          model,
          accountId
        )
        logger.info(
          `📊 Recorded Gemini usage - Input: ${usage.promptTokenCount}, Output: ${usage.candidatesTokenCount}, Total: ${usage.totalTokenCount}`
        )
      } catch (error) {
        logger.error('Failed to record Gemini usage:', error)
      }
    }

    res.json(response.response || response)
  } catch (error) {
    logger.error(`Error in standard generateContent endpoint`, {
      message: error.message,
      status: error.response?.status,
      statusText: error.response?.statusText,
      responseData: error.response?.data,
      stack: error.stack
    })

    res.status(500).json({
      error: {
        message: error.message || 'Internal server error',
        type: 'api_error'
      }
    })
  }
}

/**
 * 处理标准 Gemini API 格式的 streamGenerateContent（支持 OAuth 和 API 账户）
 */
async function handleStandardStreamGenerateContent(req, res) {
  let abortController = null
  let account = null
  let sessionHash = null
  let accountId = null
  let isApiAccount = false

  try {
    if (!ensureGeminiPermission(req, res)) {
      return undefined
    }

    // 从路径参数中获取模型名
    const model = req.params.modelName || 'gemini-2.0-flash-exp'
    sessionHash = sessionHelper.generateSessionHash(req.body)

    // 标准 Gemini API 请求体直接包含 contents 等字段
    const { contents, generationConfig, safetySettings, systemInstruction, tools, toolConfig } =
      req.body

    // 验证必需参数
    if (!contents || !Array.isArray(contents) || contents.length === 0) {
      return res.status(400).json({
        error: {
          message: 'Contents array is required',
          type: 'invalid_request_error'
        }
      })
    }

    // 构建内部 API 需要的请求格式
    const actualRequestData = {
      contents,
      generationConfig: generationConfig || {
        temperature: 0.7,
        maxOutputTokens: 4096,
        topP: 0.95,
        topK: 40
      }
    }

    if (safetySettings && safetySettings.length > 0) {
      actualRequestData.safetySettings = safetySettings
    }

    if (tools) {
      actualRequestData.tools = tools
    }

    if (toolConfig) {
      actualRequestData.toolConfig = toolConfig
    }

    // 处理 system instruction
    if (systemInstruction) {
      if (typeof systemInstruction === 'string' && systemInstruction.trim()) {
        actualRequestData.systemInstruction = {
          role: 'user',
          parts: [{ text: systemInstruction }]
        }
      } else if (systemInstruction.parts && systemInstruction.parts.length > 0) {
        const hasContent = systemInstruction.parts.some(
          (part) => part.text && part.text.trim() !== ''
        )
        if (hasContent) {
          actualRequestData.systemInstruction = {
            role: 'user',
            parts: systemInstruction.parts
          }
        }
      }
    }

    // 使用统一调度选择账号
    const schedulerResult = await unifiedGeminiScheduler.selectAccountForApiKey(
      req.apiKey,
      sessionHash,
      model,
      { allowApiAccounts: true }
    )
    ;({ accountId } = schedulerResult)
    const { accountType } = schedulerResult

    isApiAccount = accountType === 'gemini-api'
    const actualAccountId = accountId

    const version = req.path.includes('v1beta') ? 'v1beta' : 'v1'

    if (isApiAccount) {
      account = await geminiApiAccountService.getAccount(actualAccountId)
      if (!account) {
        return res.status(404).json({
          error: {
            message: 'Gemini API account not found',
            type: 'account_not_found'
          }
        })
      }

      // API Key 账户：清理 functionResponse 中标准 Gemini API 不支持的字段（如 id）
      actualRequestData.contents = sanitizeFunctionResponsesForApiKey(actualRequestData.contents)

      logger.info(
        `Standard Gemini API streamGenerateContent request (${version}) - API Key Account`,
        {
          model,
          accountId: actualAccountId,
          apiKeyId: req.apiKey?.id || 'unknown'
        }
      )
    } else {
      account = await geminiAccountService.getAccount(actualAccountId)

      logger.info(
        `Standard Gemini API streamGenerateContent request (${version}) - OAuth Account`,
        {
          model,
          projectId: account.projectId,
          apiKeyId: req.apiKey?.id || 'unknown'
        }
      )
    }

    // 创建中止控制器
    abortController = new AbortController()

    // 处理客户端断开连接
    req.on('close', () => {
      if (abortController && !abortController.signal.aborted) {
        logger.info('Client disconnected, aborting stream request')
        abortController.abort()
      }
    })

    // 解析账户的代理配置
    const proxyConfig = parseProxyConfig(account)

    let streamResponse

    if (isApiAccount) {
      // Gemini API 账户：直接使用 API Key 请求流式接口
      const apiUrl = buildGeminiApiUrl(
        account.baseUrl,
        model,
        'streamGenerateContent',
        account.apiKey,
        {
          stream: true
        }
      )

      const axiosConfig = {
        method: 'POST',
        url: apiUrl,
        data: actualRequestData,
        headers: {
          'Content-Type': 'application/json',
          'x-api-key': account.apiKey,
          'x-goog-api-key': account.apiKey
        },
        responseType: 'stream',
        signal: abortController.signal
      }

      if (proxyConfig) {
        axiosConfig.httpsAgent = ProxyHelper.createProxyAgent(proxyConfig)
        axiosConfig.httpAgent = ProxyHelper.createProxyAgent(proxyConfig)
      }

      try {
        const apiResponse = await axios(axiosConfig)
        streamResponse = apiResponse.data
      } catch (error) {
        logger.error('Gemini API stream request failed:', {
          status: error.response?.status,
          statusText: error.response?.statusText,
          data: error.response?.data
        })
        throw error
      }
    } else {
      // OAuth 账户
      const { accessToken, refreshToken } = account
      const client = await geminiAccountService.getOauthClient(
        accessToken,
        refreshToken,
        proxyConfig
      )

      let effectiveProjectId = account.projectId || account.tempProjectId || null

      if (!effectiveProjectId) {
        try {
          logger.info('📋 No projectId available, attempting to fetch from loadCodeAssist...')
          const loadResponse = await geminiAccountService.loadCodeAssist(client, null, proxyConfig)

          if (loadResponse.cloudaicompanionProject) {
            effectiveProjectId = loadResponse.cloudaicompanionProject
            await geminiAccountService.updateTempProjectId(actualAccountId, effectiveProjectId)
            logger.info(`📋 Fetched and cached temporary projectId: ${effectiveProjectId}`)
          }
        } catch (loadError) {
          logger.warn('Failed to fetch projectId from loadCodeAssist:', loadError.message)
        }
      }

      if (!effectiveProjectId) {
        return res.status(403).json({
          error: {
            message:
              'This account requires a project ID to be configured. Please configure a project ID in the account settings.',
            type: 'configuration_required'
          }
        })
      }

      logger.info('📋 Standard API 流式项目ID处理逻辑', {
        accountProjectId: account.projectId,
        tempProjectId: account.tempProjectId,
        effectiveProjectId,
        decision: account.projectId
          ? '使用账户配置'
          : account.tempProjectId
            ? '使用临时项目ID'
            : '从loadCodeAssist获取'
      })

      const userPromptId = `${crypto.randomUUID()}########0`

      streamResponse = await geminiAccountService.generateContentStream(
        client,
        { model, request: actualRequestData },
        userPromptId,
        effectiveProjectId,
        req.apiKey?.id,
        abortController.signal,
        proxyConfig
      )
    }

    // 设置 SSE 响应头
    res.setHeader('Content-Type', 'text/event-stream')
    res.setHeader('Cache-Control', 'no-cache')
    res.setHeader('Connection', 'keep-alive')
    res.setHeader('X-Accel-Buffering', 'no')

    // 处理流式响应
    let totalUsage = {
      promptTokenCount: 0,
      candidatesTokenCount: 0,
      totalTokenCount: 0
    }

    let heartbeatTimer = null
    let lastDataTime = Date.now()
    const HEARTBEAT_INTERVAL = 15000

    const sendHeartbeat = () => {
      const timeSinceLastData = Date.now() - lastDataTime
      if (timeSinceLastData >= HEARTBEAT_INTERVAL && !res.destroyed) {
        res.write('\n')
        logger.info(`💓 Sent SSE keepalive (gap: ${(timeSinceLastData / 1000).toFixed(1)}s)`)
      }
    }

    heartbeatTimer = setInterval(sendHeartbeat, HEARTBEAT_INTERVAL)

    let sseBuffer = ''

    const handleEventBlock = (evt) => {
      if (!evt.trim()) {
        return
      }

      const dataLines = evt.split(/\r?\n/).filter((line) => line.startsWith('data:'))
      if (dataLines.length === 0) {
        if (!res.destroyed) {
          res.write(`${evt}\n\n`)
        }
        return
      }

      const dataPayload = dataLines.map((line) => line.replace(/^data:\s?/, '')).join('\n')

      let processedPayload = null
      let parsed = null

      if (dataPayload === '[DONE]') {
        processedPayload = '[DONE]'
      } else {
        try {
          parsed = JSON.parse(dataPayload)

          if (parsed.usageMetadata) {
            totalUsage = parsed.usageMetadata
          } else if (parsed.response?.usageMetadata) {
            totalUsage = parsed.response.usageMetadata
          }

          processedPayload = JSON.stringify(parsed.response || parsed)
        } catch (e) {
          // 解析失败，直接转发原始 data
        }
      }

      const outputChunk = processedPayload === null ? `${evt}\n\n` : `data: ${processedPayload}\n\n`

      if (!res.destroyed) {
        res.write(outputChunk)
      }

      setImmediate(() => {
        try {
          const usageSource =
            processedPayload && processedPayload !== '[DONE]' ? processedPayload : dataPayload

          if (!usageSource || !usageSource.includes('usageMetadata')) {
            return
          }

          const usageObj = JSON.parse(usageSource)
          const usage = usageObj.usageMetadata || usageObj.response?.usageMetadata || usageObj.usage

          if (usage && typeof usage === 'object') {
            totalUsage = usage
            logger.debug('📊 Captured Gemini usage data (async):', totalUsage)
          }
        } catch (error) {
          // 提取用量失败时忽略
        }
      })
    }

    streamResponse.on('data', (chunk) => {
      try {
        lastDataTime = Date.now()

        sseBuffer += chunk.toString()
        const events = sseBuffer.split(/\r?\n\r?\n/)
        sseBuffer = events.pop() || ''

        for (const evt of events) {
          handleEventBlock(evt)
        }
      } catch (error) {
        logger.error('Error processing stream chunk:', error)
      }
    })

    streamResponse.on('end', () => {
      logger.info('Stream completed successfully')

      if (sseBuffer.trim()) {
        try {
          handleEventBlock(sseBuffer)
        } catch (flushError) {
          // 忽略 flush 期间的异常
        }
        sseBuffer = ''
      }

      if (heartbeatTimer) {
        clearInterval(heartbeatTimer)
        heartbeatTimer = null
      }

      res.end()

      if (totalUsage.totalTokenCount > 0) {
        apiKeyService
          .recordUsage(
            req.apiKey.id,
            totalUsage.promptTokenCount || 0,
            totalUsage.candidatesTokenCount || 0,
            0,
            0,
            model,
            accountId
          )
          .then(() => {
            logger.info(
              `📊 Recorded Gemini stream usage - Input: ${totalUsage.promptTokenCount}, Output: ${totalUsage.candidatesTokenCount}, Total: ${totalUsage.totalTokenCount}`
            )
          })
          .catch((error) => {
            logger.error('Failed to record Gemini usage:', error)
          })
      } else {
        logger.warn(
          `⚠️ Stream completed without usage data - totalTokenCount: ${totalUsage.totalTokenCount}`
        )
      }
    })

    streamResponse.on('error', (error) => {
      logger.error('Stream error:', error)

      if (heartbeatTimer) {
        clearInterval(heartbeatTimer)
        heartbeatTimer = null
      }

      if (!res.headersSent) {
        res.status(500).json({
          error: {
            message: error.message || 'Stream error',
            type: 'api_error'
          }
        })
      } else {
        if (!res.destroyed) {
          try {
            res.write(
              `data: ${JSON.stringify({
                error: {
                  message: error.message || 'Stream error',
                  type: 'stream_error',
                  code: error.code
                }
              })}\n\n`
            )
            res.write('data: [DONE]\n\n')
          } catch (writeError) {
            logger.error('Error sending error event:', writeError)
          }
        }
        res.end()
      }
    })
  } catch (error) {
    const normalizedError = await normalizeAxiosStreamError(error)

    logger.error(`Error in standard streamGenerateContent endpoint`, {
      message: error.message,
      status: error.response?.status,
      statusText: error.response?.statusText,
      responseData: normalizedError.parsedBody || normalizedError.rawBody,
      stack: error.stack
    })

    if (!res.headersSent) {
      const statusCode = normalizedError.status || 500
      const responseBody = {
        error: {
          message: normalizedError.message,
          type: 'api_error'
        }
      }

      if (normalizedError.status) {
        responseBody.error.upstreamStatus = normalizedError.status
      }
      if (normalizedError.statusText) {
        responseBody.error.upstreamStatusText = normalizedError.statusText
      }
      if (normalizedError.parsedBody && typeof normalizedError.parsedBody === 'object') {
        responseBody.error.upstreamResponse = normalizedError.parsedBody
      } else if (normalizedError.rawBody) {
        responseBody.error.upstreamRaw = normalizedError.rawBody
      }

      return res.status(statusCode).json(responseBody)
    }
  } finally {
    if (abortController) {
      abortController = null
    }
  }
}

// ============================================================================
// 导出
// ============================================================================

module.exports = {
  // 工具函数
  generateSessionHash,
  checkPermissions,
  ensureGeminiPermission,
  ensureGeminiPermissionMiddleware,
  applyRateLimitTracking,
  parseProxyConfig,
  normalizeAxiosStreamError,

  // OpenAI 兼容格式处理函数
  handleMessages,

  // 模型相关处理函数
  handleModels,
  handleModelDetails,

  // 使用统计和 API Key 信息
  handleUsage,
  handleKeyInfo,

  // v1internal 格式处理函数
  handleSimpleEndpoint,
  handleLoadCodeAssist,
  handleOnboardUser,
  handleCountTokens,
  handleGenerateContent,
  handleStreamGenerateContent,

  // 标准 Gemini API 格式处理函数
  handleStandardGenerateContent,
  handleStandardStreamGenerateContent
}
